import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart';

class GamePage extends StatefulWidget {
  const GamePage({Key? key}) : super(key: key);

  @override
  _GamePageState createState() => _GamePageState();
}

class _GamePageState extends State<GamePage> {
  // 记录用户点击的StreamController
  final StreamController<int> controller = StreamController.broadcast();
  // 求和用的StreamController
  final StreamController scoreController = StreamController.broadcast();

  @override
  void dispose() {
    controller.close();
    scoreController.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: StreamBuilder(
                stream: scoreController.stream.transform(TallyTransformer()),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    return Text('Score:${snapshot.data}');
                  } else {
                    return const Text('Score:0');
                  }
                })),
        body: Stack(
          children: [
            ...List.generate(
                10,
                (_) => Puzzle(
                    stream: controller.stream,
                    scoreController: scoreController)),
            Align(
              alignment: Alignment.bottomCenter,
              child: KeyPad(
                  controller: controller, scoreController: scoreController),
            )
          ],
        ));
  }
}

// 将一个stream转换成另外一个steam
class TallyTransformer implements StreamTransformer {
  final StreamController _streamController = StreamController();
  int sum = 0;
  @override
  Stream bind(stream) {
    stream.listen((event) {
      sum += (event as int);
      _streamController.add(sum);
    });
    return _streamController.stream;
  }

  @override
  StreamTransformer<RS, RT> cast<RS, RT>() => StreamTransformer.castFrom(this);
}

class Puzzle extends StatefulWidget {
  const Puzzle({Key? key, required this.stream, required this.scoreController})
      : super(key: key);
  final Stream<int> stream;
  final StreamController scoreController;

  @override
  _PuzzleState createState() => _PuzzleState();
}

class _PuzzleState extends State<Puzzle> with TickerProviderStateMixin {
  late int a;
  late int b;
  late double l;
  late Color color;
  late AnimationController _controller;

  reset() {
    a = Random().nextInt(4);
    b = Random().nextInt(4);
    l = Random().nextDouble() * 350;
    color = Colors.primaries[Random().nextInt(18)][200]!;
    _controller.duration =
        Duration(milliseconds: Random().nextInt(5000) + 5000);
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  void initState() {
    _controller = AnimationController(
      vsync: this,
    );
    reset();
    _controller.forward(from: Random().nextDouble());
    // 重置
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        reset();
        _controller.forward(from: 0);
        widget.scoreController.add(-2);
      }
    });

    widget.stream.listen(
      (event) {
        if (event == a + b) {
          reset();
          _controller.forward(from: 0);
          widget.scoreController.add(5);
        }
      },
    );

    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
        animation: _controller,
        builder: (context, child) {
          return Positioned(
            left: l,
            top: _controller.value * 600 - 100,
            child: Container(
                padding: const EdgeInsets.all(10),
                decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(20),
                    color: color.withOpacity(0.6),
                    border: Border.all(color: Colors.black)),
                child: Text("$a+$b")),
          );
        });
  }
}

class KeyPad extends StatelessWidget {
  const KeyPad(
      {Key? key, required this.controller, required this.scoreController})
      : super(key: key);
  final StreamController controller;
  final StreamController scoreController;

  @override
  Widget build(BuildContext context) {
    return GridView.count(
      shrinkWrap: true,
      crossAxisCount: 3,
      childAspectRatio: 2 / 1,
      children: List.generate(9, (index) {
        return TextButton(
          style: TextButton.styleFrom(
            backgroundColor: Colors.primaries[index][100],
            shape: const ContinuousRectangleBorder(),
          ),
          onPressed: () {
            controller.add(index + 1);
            scoreController.add(-2);
          },
          child: Text(
            '${index + 1}',
            style: const TextStyle(fontSize: 20),
          ),
        );
      }),
    );
  }
}
